package com.situ.util;

import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class BaseServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String o = req.getParameter("o");
        //用反射找方法执行
        Method m = null;
        try {
            Method[] methods = this.getClass().getDeclaredMethods();
            for (Method method : methods) {
                if (method.getName().equals(o)) {
                    m = method;
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        invokeMethod(m, req, resp);
    }

    //执行方法
    private void invokeMethod(Method m, HttpServletRequest req, HttpServletResponse resp) {
        try {
            //获取方法中参数的类型
            Class[] types = m.getParameterTypes();
            //获取方法中所有的参数
            Parameter[] parameters = m.getParameters();
            //执行方法时传进去的参数
            Object[] params = new Object[types.length];
            //遍历所有的参数类型
            for (int i = 0; i < types.length; i++) {
                if (types[i].equals(HttpServletRequest.class)) {
                    params[i] = req;
                } else if (types[i].equals(HttpServletResponse.class)) {
                    params[i] = resp;
                } else if (types[i].equals(Integer.class)) {//兼容整数类型
                    Param a = parameters[i].getDeclaredAnnotation(Param.class);
                    if (a != null) {
                        String value = req.getParameter(a.value());
                        if (value != null && !value.isEmpty()) {
                            params[i] = Integer.parseInt(value);
                        }
                    }
                } else if (types[i].equals(String.class)) {//兼容字符串类型
                    Param a = parameters[i].getDeclaredAnnotation(Param.class);
                    if (a != null) {
                        String value = req.getParameter(a.value());
                        params[i] = value;
                    }
                } else {//兼容对象类型
                    Object t = types[i].newInstance();
                    //获取所有的成员变量
                    Field[] fields = types[i].getDeclaredFields();
                    for (Field f : fields) {
                        //获取成员变量名对应的参数值
                        String v = req.getParameter(f.getName());
                        if (v == null || v.isEmpty()) {
                            continue;
                        }
                        //TODO　扩展复杂类型中其他的数据类型
                        if (f.getType().equals(Integer.class)) {
                            f.setAccessible(true);
                            f.set(t, Integer.parseInt(v));
                        } else if (f.getType().equals(String.class)) {
                            f.setAccessible(true);
                            f.set(t, v);
                        }
                    }
                    params[i] = t;
                }
            }
            m.setAccessible(true);
            Object result = m.invoke(this, params);
            if (result != null) {
                if (result instanceof String) {
                    req.getRequestDispatcher("/WEB-INF/" + result + ".jsp").forward(req, resp);
                } else {
                    String src = new ObjectMapper().writeValueAsString(result);
                    resp.setContentType("application/json;charset=utf-8");
                    resp.getWriter().write(src);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
